#include "url.h"
#include "queue.h"
#include "hash_table.h"
#include "global.h"
#include "dns.h"
#include "download.h"

int main()
{
	global_t			*global;
	int					i, err, n, max_num_url;
	void 				*tret;
	pthread_attr_t 		cattr, qattr, dattr;
	struct sched_param 	cparam, qparam, dparam;

	pthread_attr_init(&cattr);
	pthread_attr_init(&qattr);
	pthread_attr_init(&dattr);
	pthread_attr_setschedpolicy(&cattr, SCHED_RR);
	pthread_attr_setschedpolicy(&qattr, SCHED_RR);
	pthread_attr_setschedpolicy(&dattr, SCHED_RR);
	cparam.sched_priority = 0;
	qparam.sched_priority = 20;
	dparam.sched_priority = 0;
	pthread_attr_setschedparam(&cattr, &cparam);
	pthread_attr_setschedparam(&qattr, &qparam);
	pthread_attr_setschedparam(&dattr, &dparam);


	// 初始化global
	global = (global_t *)malloc(sizeof(global_t));
	global->max_conn = 100;
	max_num_url = 2000000;
	global->start_url = 
		"http://kiwitobes.com/wiki/Categorical_list_of_programming_languages.html";
	//"http://gcc.gnu.org/index.html";
	//"http://www.apache.org/index.html";
	//"http://www.kohala.com/start/apue.html";
	global->url_table = ht_create(max_num_url);
	global->host_table = ht_create(max_num_url);
	global->url_queue = q_create(max_num_url);
	global->conn_queue = q_create(global->max_conn);
	global->dl_list = list_create(global->max_conn);

	global->count = 0;

	q_push(global->url_queue, global->start_url);
	global->conn = (conn_t *)malloc(sizeof(conn_t)*global->max_conn);
	for (i = 0; i < global->max_conn; i++) {
		init_conn(&global->conn[i], NULL);
		q_push(global->conn_queue, &global->conn[i]);
	}

	global->dns = dns_init(dns_callback);

	FD_ZERO(&global->dns_set);
	FD_SET(dns_get_fd(global->dns), &global->dns_set);
	dns_request(global->dns, url_get_host(global->start_url), DNS_A_RECORD);
	for (;;) {
		if (select(dns_get_fd(global->dns)+1,
					&global->dns_set, NULL, NULL, NULL) > 0) {
			dns_poll(global, global->dns);
			break;
		} 
	}

	sem_init(&global->dsem, 0, 0);
	sem_init(&global->csem, 0, global->max_conn);
	sem_init(&global->usem, 0, 1);

	err = pthread_create(&(global->qtid), &qattr, query_thread, global);
	if (err != 0) {
		printf("create query_thread error...\n");
	}
	err = pthread_create(&global->dtid, &dattr, dl_thread, global);
	if (err != 0) {
		printf("create dl_thread error...\n");
	}

	//todo: 使用线程池来connect socket
	for (;;) {
		n = q_size(global->url_queue);
		n = MIN(n, MAX_CONN_THREAD);
		for (i = 0; i < n; i++) {
			err = pthread_create(global->ctid+i, &cattr, conn_thread, global);
		}
		for (i = 0; i < n; i++) {
			pthread_join(global->ctid[i], &tret);
		}
	}

	pthread_join(global->qtid, &tret);
	pthread_join(global->dtid, &tret);
	//pthread_join(global->ctid, &tret);

	ht_destroy(global->url_table);
	ht_destroy(global->host_table);
	q_destroy(global->url_queue);
	q_destroy(global->conn_queue);
	list_destroy(global->dl_list);
	free(global->conn);
	free(global);

	return 0;
}
